package com.hospital.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hospital.entity.Department;
import com.hospital.entity.Schedule;
import com.hospital.entity.User;
import com.hospital.mapper.ScheduleMapper;
import com.hospital.service.DepartmentService;
import com.hospital.service.ScheduleService;
import com.hospital.service.UserService;
import com.hospital.vo.DoctorScheduleVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 排班服务实现类
 *
 * @author Hospital Management System
 */
@Service
@RequiredArgsConstructor
public class ScheduleServiceImpl extends ServiceImpl<ScheduleMapper, Schedule> implements ScheduleService {

    private final ScheduleMapper scheduleMapper;
    private final UserService userService;
    private final DepartmentService departmentService;

    @Override
    public List<Schedule> getDoctorSchedules(Long doctorId, LocalDate startDate, LocalDate endDate) {
        return scheduleMapper.getDoctorSchedules(doctorId, startDate, endDate);
    }

    @Override
    public List<Schedule> getCurrentDoctorSchedules(Long doctorId) {
        LocalDate today = LocalDate.now();
        LocalDate endDate = today.plusDays(30); // 查看未来30天的排班
        return getDoctorSchedules(doctorId, today, endDate);
    }

    @Override
    @Transactional
    public void updateScheduleStatus(Long scheduleId, Integer status, String remark) {
        Schedule schedule = getById(scheduleId);
        if (schedule != null) {
            schedule.setStatus(status);
            schedule.setRemark(remark);
            updateById(schedule);
        }
    }

    @Override
    public List<Schedule> getAllSchedules(LocalDate startDate, LocalDate endDate) {
        return scheduleMapper.getAllSchedules(startDate, endDate);
    }

    @Override
    public Map<String, Object> getSchedulesWithPagination(Long departmentId, Integer status, 
                                                           LocalDate startDate, LocalDate endDate, 
                                                           Integer page, Integer size) {
        // 创建分页对象
        Page<Schedule> pageObj = new Page<>(page, size);
        
        // 构建查询条件
        QueryWrapper<Schedule> wrapper = new QueryWrapper<>();
        
        // 日期范围筛选
        if (startDate != null) {
            wrapper.ge("schedule_date", startDate);
        }
        if (endDate != null) {
            wrapper.le("schedule_date", endDate);
        }
        
        // 科室筛选
        if (departmentId != null) {
            wrapper.eq("department_id", departmentId);
        }
        
        // 状态筛选
        if (status != null) {
            wrapper.eq("status", status);
        }
        
        // 按排班日期和时段排序
        wrapper.orderByAsc("schedule_date", "time_slot");
        
        // 执行分页查询
        IPage<Schedule> pageResult = page(pageObj, wrapper);
        
        // 获取查询结果
        List<Schedule> schedules = pageResult.getRecords();
        
        // 填充医生姓名和科室名称等关联信息
        fillRelatedInfo(schedules);
        
        // 构建返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("list", schedules);
        result.put("total", pageResult.getTotal());
        result.put("page", pageResult.getCurrent());
        result.put("size", pageResult.getSize());
        result.put("pages", pageResult.getPages());
        
        return result;
    }

    @Override
    public List<Schedule> getSchedulesByDepartment(Long departmentId, LocalDate startDate, LocalDate endDate) {
        return scheduleMapper.getSchedulesByDepartment(departmentId, startDate, endDate);
    }

    @Override
    public Map<String, Object> getScheduleStatistics(LocalDate startDate, LocalDate endDate) {
        // 使用MyBatis Plus的查询构造器来获取统计数据
        QueryWrapper<Schedule> wrapper = new QueryWrapper<>();
        
        // 日期范围筛选
        if (startDate != null) {
            wrapper.ge("schedule_date", startDate);
        }
        if (endDate != null) {
            wrapper.le("schedule_date", endDate);
        }
        
        // 查询总数
        long totalSchedules = count(wrapper);
        
        // 查询各状态的数量
        QueryWrapper<Schedule> normalWrapper = new QueryWrapper<>();
        if (startDate != null) {
            normalWrapper.ge("schedule_date", startDate);
        }
        if (endDate != null) {
            normalWrapper.le("schedule_date", endDate);
        }
        normalWrapper.eq("status", 1);
        long normalSchedules = count(normalWrapper);
        
        QueryWrapper<Schedule> cancelledWrapper = new QueryWrapper<>();
        if (startDate != null) {
            cancelledWrapper.ge("schedule_date", startDate);
        }
        if (endDate != null) {
            cancelledWrapper.le("schedule_date", endDate);
        }
        cancelledWrapper.eq("status", 0);
        long cancelledSchedules = count(cancelledWrapper);
        
        QueryWrapper<Schedule> fullWrapper = new QueryWrapper<>();
        if (startDate != null) {
            fullWrapper.ge("schedule_date", startDate);
        }
        if (endDate != null) {
            fullWrapper.le("schedule_date", endDate);
        }
        fullWrapper.eq("status", 2);
        long fullSchedules = count(fullWrapper);
        
        Map<String, Object> result = new HashMap<>();
        result.put("totalSchedules", totalSchedules);
        result.put("normalSchedules", normalSchedules);
        result.put("cancelledSchedules", cancelledSchedules);
        result.put("fullSchedules", fullSchedules);
        
        return result;
    }

    @Override
    @Transactional
    public void createSchedule(Schedule schedule) {
        // 检查冲突
        if (hasConflict(schedule.getDoctorId(), schedule.getScheduleDate(), schedule.getTimeSlot())) {
            throw new RuntimeException("该时段已有排班，无法重复安排");
        }
        
        // 设置初始状态
        schedule.setBookedCount(0);
        schedule.setStatus(1); // 正常状态
        
        save(schedule);
    }

    @Override
    @Transactional
    public void updateSchedule(Schedule schedule) {
        if (schedule.getId() == null) {
            throw new RuntimeException("更新排班时ID不能为空");
        }
        
        // 检查排班是否存在
        Schedule existingSchedule = getById(schedule.getId());
        if (existingSchedule == null) {
            throw new RuntimeException("排班不存在");
        }
        
        // 如果修改了时间或医生，需要检查冲突（但排除自己）
        if (!existingSchedule.getDoctorId().equals(schedule.getDoctorId()) ||
            !existingSchedule.getScheduleDate().equals(schedule.getScheduleDate()) ||
            !existingSchedule.getTimeSlot().equals(schedule.getTimeSlot())) {
            
            // 检查新的时间是否有冲突
            QueryWrapper<Schedule> conflictWrapper = new QueryWrapper<>();
            conflictWrapper.eq("doctor_id", schedule.getDoctorId())
                          .eq("schedule_date", schedule.getScheduleDate())
                          .eq("time_slot", schedule.getTimeSlot())
                          .ne("id", schedule.getId()); // 排除当前记录
            
            if (count(conflictWrapper) > 0) {
                throw new RuntimeException("该时段已有排班，无法重复安排");
            }
        }
        
        // 更新排班信息
        updateById(schedule);
    }

    @Override
    @Transactional
    public void batchCreateSchedules(List<Schedule> schedules) {
        for (Schedule schedule : schedules) {
            createSchedule(schedule);
        }
    }

    @Override
    @Transactional
    public void deleteSchedule(Long scheduleId) {
        Schedule schedule = getById(scheduleId);
        if (schedule != null && schedule.getBookedCount() > 0) {
            throw new RuntimeException("该排班已有患者预约，无法删除");
        }
        removeById(scheduleId);
    }

    @Override
    public boolean hasConflict(Long doctorId, LocalDate date, Integer timeSlot) {
        QueryWrapper<Schedule> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("doctor_id", doctorId)
                   .eq("schedule_date", date)
                   .eq("time_slot", timeSlot);
        
        return count(queryWrapper) > 0;
    }

    @Override
    public Map<String, Object> getDoctorWorkload(Long doctorId, LocalDate startDate, LocalDate endDate) {
        List<Schedule> schedules = getDoctorSchedules(doctorId, startDate, endDate);
        
        Map<String, Object> workload = new HashMap<>();
        workload.put("totalSchedules", schedules.size());
        workload.put("totalPatients", schedules.stream().mapToInt(s -> s.getBookedCount() != null ? s.getBookedCount() : 0).sum());
        workload.put("workDays", schedules.stream().map(Schedule::getScheduleDate).distinct().count());
        
        return workload;
    }

    /**
     * 填充排班的关联信息（医生姓名、科室名称）
     */
    private void fillRelatedInfo(List<Schedule> schedules) {
        if (schedules == null || schedules.isEmpty()) {
            return;
        }

        // 获取所有医生ID和科室ID
        List<Long> doctorIds = schedules.stream()
                .map(Schedule::getDoctorId)
                .filter(id -> id != null)
                .distinct()
                .collect(Collectors.toList());

        List<Long> departmentIds = schedules.stream()
                .map(Schedule::getDepartmentId)
                .filter(id -> id != null)
                .distinct()
                .collect(Collectors.toList());

        // 批量查询医生信息
        Map<Long, User> doctorMap = new HashMap<>();
        if (!doctorIds.isEmpty()) {
            List<User> doctors = userService.listByIds(doctorIds);
            doctorMap = doctors.stream()
                    .collect(Collectors.toMap(User::getId, user -> user));
        }

        // 批量查询科室信息
        Map<Long, Department> departmentMap = new HashMap<>();
        if (!departmentIds.isEmpty()) {
            List<Department> departments = departmentService.listByIds(departmentIds);
            departmentMap = departments.stream()
                    .collect(Collectors.toMap(Department::getId, dept -> dept));
        }

        // 填充关联信息
        final Map<Long, User> finalDoctorMap = doctorMap;
        final Map<Long, Department> finalDepartmentMap = departmentMap;
        
        schedules.forEach(schedule -> {
            // 填充医生姓名
            if (schedule.getDoctorId() != null && finalDoctorMap.containsKey(schedule.getDoctorId())) {
                User doctor = finalDoctorMap.get(schedule.getDoctorId());
                schedule.setDoctorName(doctor.getName());
            }

            // 填充科室名称
            if (schedule.getDepartmentId() != null && finalDepartmentMap.containsKey(schedule.getDepartmentId())) {
                Department department = finalDepartmentMap.get(schedule.getDepartmentId());
                schedule.setDepartmentName(department.getName());
            }
        });
    }

    @Override
    public long countActiveDoctorsToday() {
        LocalDate today = LocalDate.now();
        
        // 构建查询条件
        QueryWrapper<Schedule> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("schedule_date", today)
                   .eq("deleted", 0)
                   .eq("status", 1);  // 1表示正常状态
        
        // 统计不重复的医生数量
        return baseMapper.selectList(queryWrapper)
                .stream()
                .map(Schedule::getDoctorId)
                .distinct()
                .count();
    }

    @Override
    @Transactional(readOnly = true)
    public List<DoctorScheduleVO> getSchedulesByDateAndDepartment(LocalDate date, Long departmentId) {
        // 获取指定日期和科室的所有排班记录
        List<Schedule> schedules = lambdaQuery()
                .eq(Schedule::getDepartmentId, departmentId)
                .eq(Schedule::getScheduleDate, date)
                .eq(Schedule::getDeleted, 0)  // 只查询未删除的记录
                .eq(Schedule::getStatus, 1)   // 只查询正常状态的排班
                .list();

        // 获取所有涉及的医生ID
        List<Long> doctorIds = schedules.stream()
                .map(Schedule::getDoctorId)
                .distinct()
                .collect(Collectors.toList());

        // 批量查询医生信息
        final Map<Long, User> doctorMap;  // 声明为final
        if (!doctorIds.isEmpty()) {
            List<User> doctors = userService.listByIds(doctorIds);
            doctorMap = doctors.stream()
                    .collect(Collectors.toMap(User::getId, doctor -> doctor));
        } else {
            doctorMap = new HashMap<>();
        }

        // 按医生ID分组
        Map<Long, List<Schedule>> doctorSchedules = schedules.stream()
                .collect(Collectors.groupingBy(Schedule::getDoctorId));

        List<DoctorScheduleVO> result = new ArrayList<>();

        // 处理每个医生的排班信息
        doctorSchedules.forEach((doctorId, doctorScheduleList) -> {
            DoctorScheduleVO doctorScheduleVO = new DoctorScheduleVO();
            User doctor = doctorMap.get(doctorId);
            
            if (doctor != null) {
                doctorScheduleVO.setDoctorId(doctorId);
                doctorScheduleVO.setDoctorName(doctor.getName());
                doctorScheduleVO.setDoctorTitle(doctor.getTitle());  // 从医生信息中获取职称

                // 处理时间段信息
                List<DoctorScheduleVO.TimeSlotVO> timeSlots = doctorScheduleList.stream()
                        .map(schedule -> {
                            DoctorScheduleVO.TimeSlotVO timeSlot = new DoctorScheduleVO.TimeSlotVO();
                            timeSlot.setScheduleId(schedule.getId());
                            // 使用格式化后的时间字符串
                            timeSlot.setTime(formatTimeSlot(schedule.getStartTime(), schedule.getEndTime()));
                            // 计算剩余号源
                            int remaining = schedule.getAvailableCount() - (schedule.getBookedCount() != null ? schedule.getBookedCount() : 0);
                            timeSlot.setRemainingQuota(remaining);
                            return timeSlot;
                        })
                        .collect(Collectors.toList());

                doctorScheduleVO.setTimeSlots(timeSlots);
                result.add(doctorScheduleVO);
            }
        });

        return result;
    }

    /**
     * 格式化时间段字符串
     */
    private String formatTimeSlot(LocalTime startTime, LocalTime endTime) {
        if (startTime == null || endTime == null) {
            return "";
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
        return startTime.format(formatter) + "-" + endTime.format(formatter);
    }
} 